package com.example.soss.config;

import com.alibaba.fastjson.JSON;
import com.example.soss.entity.Result;
import com.example.soss.entity.ResultEnum;
import com.example.soss.entity.Student;
import com.example.soss.service.StudentService;
import com.example.soss.util.JwtTokenUtil;
import com.example.soss.util.UserContextHolder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Configuration
public class SecurityCofig extends WebSecurityConfigurerAdapter {


    @Autowired
    private StudentService studentService;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;


    @Value("${jwt.tokenHeader}")
    private String tokenHeader;

    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Value("${jwt.expiration}")
    private int expiration;

    @Value("${server.servlet.context-path}")
    private String contextPath;



    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/static/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.csrf().disable();

        http.authorizeRequests()
                .antMatchers("/js/**", "/resources/**").permitAll()
                .antMatchers("/toLogin", "/doLogin", "/captcha").permitAll()
                .antMatchers("/deleteCourse", "/addCourse", "/updateCourse").hasAuthority("admin")
                .anyRequest().authenticated();



        http.logout().logoutUrl("/fdsfsewuhd");


        //对拦截的请求预处理
        http.addFilterBefore(new OncePerRequestFilter() {
            @Override
            protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
                String token = null;
                Cookie[] cookies = request.getCookies();
                if (cookies != null) {
                    for (Cookie cookie : cookies) {
                        if (cookie.getName().equals(tokenHeader)) {
                            token = cookie.getValue();
                            break;
                        }
                    }
                }

                //如果存在token
                if (!StringUtils.isBlank(token) && token.startsWith(tokenHead)) {
                    String jwt = token.substring(tokenHead.length() + 1);
                    String username = jwtTokenUtil.getUsername(jwt);
                    //
                    Student student = studentService.getStudentByUsername(username);

                    if (jwtTokenUtil.isValid(jwt, student)) {

                        //token有效
                        UserContextHolder.setUser(student);
                        Authentication authentication = new UsernamePasswordAuthenticationToken(student, null,
                                studentService.getAuthorities(student.getId()));
                        SecurityContextHolder.getContext().setAuthentication(authentication);

                        //刷新token
                        String newToken = jwtTokenUtil.refreshToken(jwt);
                        if (newToken != null) {
                            Cookie cookie = new Cookie(tokenHeader, newToken);
                            cookie.setPath(contextPath);
                            cookie.setMaxAge(expiration);
                            response.addCookie(cookie);
                        }
                    }

                }
                filterChain.doFilter(request, response);
            }
        }, UsernamePasswordAuthenticationFilter.class);




        http.exceptionHandling()
                .authenticationEntryPoint(new AuthenticationEntryPoint() {
                    @Override
                    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {

                        String xRequestedWith = request.getHeader("x-requested-with");
                        if ("XMLHttpRequest".equals(xRequestedWith)) {
                            response.setContentType("application/json");
                            response.setCharacterEncoding("UTF-8");
                            PrintWriter writer = response.getWriter();
                            writer.write(JSON.toJSONString(Result.failure(ResultEnum.NOT_LOGIN)));
                            writer.flush();
                            writer.close();
                        } else {
                            response.sendRedirect(request.getContextPath() + "/toLogin");
                        }


                    }
                })
                .accessDeniedHandler(new AccessDeniedHandler() {
                    @Override
                    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {

                        String xRequestedWith = request.getHeader("x-requested-with");
                        if ("XMLHttpRequest".equals(xRequestedWith)) {
                            response.setContentType("application/json");
                            response.setCharacterEncoding("UTF-8");
                            PrintWriter writer = response.getWriter();
                            writer.write(JSON.toJSONString(Result.failure(ResultEnum.ACCESS_DENIED)));
                            writer.flush();
                            writer.close();
                        } else {
                            response.sendRedirect(request.getContextPath() + "/403");
                        }
                    }
                });

    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
